#!/usr/bin/python
# -*- coding: utf-8 -*-
import time
import multiprocessing.queues as mqueue
import pymongo
import multiprocessing
import threading

class SafeMongoClient(pymongo.MongoClient):
    def __init__(self, host=None, port=None):
        pymongo.MongoClient.__init__(self, host, port, w=1, j=True)
        
# Daemon Factory
class DaemonFactory(object):
    @staticmethod
    def get_daemon(name, function, arguments, process=False):
        if process:
            p = multiprocessing.Process(target=function, name=name, args=arguments)
            p.daemon = False
            return p
        else:
            t = threading.Thread(target=function, name=name, args=arguments)
            t.daemon = True
            return t

def get_serial(label, serial_queue):
    mongo_client = SafeMongoClient()
    db = mongo_client['serial_database']
    serial_collection = db['serial']
    while True:
        try:
            serial_number = serial_collection.find_and_modify(query={'label': label}, update={"$inc": {'serial': 1}}, upsert=True, new=True)
            serial_queue.put_nowait("%s" % (str(serial_number['serial'])))
            time.sleep(1)
        except:
            pass


if __name__ == '__main__':
    try:
        list_proc = []
        out_queue = mqueue.Queue()
        for i in range(10):
            omen_proc = DaemonFactory.get_daemon("serial_generator%s" % (str(i)), get_serial, ("test", out_queue,), True)
            omen_proc.start()
            list_proc.append(omen_proc)
        
        dico_test = {}
        while True:
            try:
                serial = out_queue.get(timeout=3)
                if dico_test.has_key(serial):
                    raise StandardError("La valeur %s est en double" % (serial))
                else:
                    dico_test[serial] = "toto"
                print(serial)
            except mqueue.Empty:
                time.sleep(3)
            
    except Exception, e:
        print (str(e))
        for proc in list_proc:
            proc.terminate()
        for proc in list_proc:
            proc.join()
        
    
        
